// Update.h

#ifndef __COMMON_UPDATE_H
#define __COMMON_UPDATE_H

#include "Common/FileSystem/Wildcard.h"

#include "ArchiveOpenCallback.h"
#include "LoadCodecs.h"
#include "Common/Props/Property.h"
#include "UpdateAction.h"
#include "UpdateCallback.h"

#include <vector>
#include <deque>

namespace Common
{

namespace Archive
{

struct CArchivePath
{
  CString OriginalPath;

  CString Prefix;   // path(folder) prefix including slash
  CString Name; // base name
  CString BaseExtension; // archive type extension or "exe" extension
  CString VolExtension;  // archive type extension for volumes

  bool Temp;
  CString TempPrefix;  // path(folder) for temp location
  CString TempPostfix;

  CArchivePath(): Temp(false) {};
  
  void ParseFromPath(const CString &path)
  {
    OriginalPath = path;

    Common::FileSystem::SplitPathToParts(path, Prefix, Name);
    int dotPos = Name.ReverseFind(L'.');
    if (dotPos < 0)
      return;
    if (dotPos == Name.GetLength() - 1)
    {
      Name = Name.Left(dotPos);
      BaseExtension.Empty();
      return;
    }
    if (BaseExtension.CompareNoCase(Name.Mid(dotPos + 1)) == 0)
    {
      BaseExtension = Name.Mid(dotPos + 1);
      Name = Name.Left(dotPos);
    }
    else
      BaseExtension.Empty();
  }

  CString GetPathWithoutExt() const
  {
    return Prefix + Name;
  }

  CString GetFinalPath() const
  {
    CString path = GetPathWithoutExt();
    if (!BaseExtension.IsEmpty())
      path += CString(L'.') + BaseExtension;
    return path;
  }

  
  CString GetTempPath() const
  {
    CString path = TempPrefix + Name;
    if (!BaseExtension.IsEmpty())
      path += CString(L'.') + BaseExtension;
    path += L".tmp";
    path += TempPostfix;
    return path;
  }
};

struct CUpdateArchiveCommand
{
  CString UserArchivePath;
  CArchivePath ArchivePath;
  Update::CActionSet ActionSet;
};

struct CCompressionMethodMode
{
  int FormatIndex;
  std::vector<Props::CProperty> Properties;
  CCompressionMethodMode(): FormatIndex(-1) {}
};

struct CUpdateOptions
{
  CCompressionMethodMode MethodMode;

  std::deque<std::shared_ptr<CUpdateArchiveCommand> > Commands;
  bool UpdateArchiveItself;
  CArchivePath ArchivePath;
  
  bool SfxMode;
  CString SfxModule;
  
  bool OpenShareForWrite;

  bool StdInMode;
  CString StdInFileName;
  bool StdOutMode;
  
  bool EMailMode;
  bool EMailRemoveAfter;
  CString EMailAddress;

  CString WorkingDir;

  bool Init(const CCodecs *codecs, const std::vector<int> &formatIndices, const CString &arcPath);

  CUpdateOptions():
    UpdateArchiveItself(true),
    SfxMode(false),
    StdInMode(false),
    StdOutMode(false),
    EMailMode(false),
    EMailRemoveAfter(false),
    OpenShareForWrite(false)
      {};

  void SetAddActionCommand()
  {
    Commands.clear();
	std::shared_ptr<CUpdateArchiveCommand> c = std::make_shared<CUpdateArchiveCommand>();
    c->ActionSet = Update::kAddActionSet;
	Commands.push_back(c);
  }

  std::vector<UINT64> VolumesSizes;
};

struct CErrorInfo
{
  DWORD SystemError;
  CString FileName;
  CString FileName2;
  CString Message;
  // CStringVector ErrorPaths;
  // std::vector<DWORD> ErrorCodes;
  CErrorInfo(): SystemError(0) {};
};

struct CUpdateErrorInfo: public CErrorInfo
{
};



struct IUpdateCallbackUI2: public IUpdateCallbackUI
{
  // INTERFACE IUpdateCallbackUI 
  STDMETHOD(SetTotal)(UINT64 size) PURE;
  STDMETHOD(SetCompleted)(const UINT64 *completeValue) PURE;
  STDMETHOD(SetRatioInfo)(const UINT64 *inSize, const UINT64 *outSize) PURE;
  STDMETHOD(CheckBreak)() PURE;
  STDMETHOD(Finilize)() PURE;
  STDMETHOD(SetNumFiles)(UINT64 numFiles) PURE;
  STDMETHOD(GetStream)(const wchar_t *name, bool isAnti) PURE;
  STDMETHOD(OpenFileError)(const wchar_t *name, DWORD systemError) PURE;
  STDMETHOD(SetOperationResult)(INT32 operationResult) PURE;
  STDMETHOD(CryptoGetTextPassword2)(INT32 *passwordIsDefined, BSTR *password) PURE;
  STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE;
  /* STDMETHOD(ShowDeleteFile)(const wchar_t *name)PURE; */ 
  /* STDMETHOD(CloseProgress)() { return S_OK; }; */

  //INTERFACE IUpdateCallbackUI2
  STDMETHOD(OpenResult)(const wchar_t *name, HRESULT result) PURE;
  STDMETHOD(StartScanning)() PURE;
  STDMETHOD(ScanProgress)(UINT64 numFolders, UINT64 numFiles, const wchar_t *path) PURE;
  STDMETHOD(CanNotFindError)(const wchar_t *name, DWORD systemError) PURE;
  STDMETHOD(FinishScanning)() PURE;
  STDMETHOD(StartArchive)(const wchar_t *name, bool updating) PURE;
  STDMETHOD(FinishArchive)() PURE;
	
};

HRESULT UpdateArchive(
	CCodecs *codecs,
    const Common::FileSystem::Wildcard::CCensor &censor,
    CUpdateOptions &options,
    CUpdateErrorInfo &errorInfo,
    IOpenCallbackUI *openCallback,
    IUpdateCallbackUI2 *callback);

}
}
#endif
